package com.datang.litejvm.cmd;

import com.datang.litejvm.clz.Class;
import com.datang.litejvm.constant.ConstantFieldRefInfo;
import com.datang.litejvm.constant.ConstantNameAndTypeInfo;
import com.datang.litejvm.constant.ConstantPool;
import com.datang.litejvm.engin.ExecutionResult;
import com.datang.litejvm.engin.JavaObject;
import com.datang.litejvm.engin.StackFrame;

public class PutFieldCmd extends TwoOperandCmd {
    public PutFieldCmd(ConstantPool pool, String opCode) {
        super(pool, opCode);
    }

    @Override
    public String toString() {
        return super.toString();
    }

    /**
     * @author: 顶风少年
     * @Description: 设置对象字段
     * 无符号数 indexbyte1 和 indexbyte2 用于构建一个当前类（§2.6）的运
     * 行时常量池的索引值，构建方式为（indexbyte1 << 8）| indexbyte2，
     * 该索引所指向的运行时常量池项应当是一个字段（§5.1）的符号引用，它包
     * 含了字段的名称和描述符，以及包含该字段的类的符号引用。objectref 所
     * 引用的对象不能是数组类型，如果取值的字段是 protected 的（§4.6），并
     * 且这个字段是当前类的父类成员，并且这个字段没有在同一个运行时包
     * （§5.3）中定义过，那 objectref 所指向的对象的类型必须为当前类或者
     * 当前类的子类。
     * 这个字段的符号引用是已被解析过的（§5.4.3.2）。被 putfield 指令存储
     * 到字段中的 value 值的类型必须与字段的描述符相匹配（§4.3.2）。如果字
     * 段描述符的类型是 boolean、byte、char、short 或者 int，那么 value
     * 必须为 int 类型。如果字段描述符的类型是 float、long 或者 double，那
     * value 的类型必须相应为 float、long 或者 double。如果字段描述符的类
     * 型是 reference 类型，那 value 必须为一个可与之匹配（JLS §5.2）的
     * 类型。如果字段被声明为 final 的，那就只有在当前类的实例初始化方法
     * （<init>）中设置当前类的 final 字段才是合法的。
     * 指令执行时，value 和 objectref 从操作数栈中出栈，objectref 必须为
     * reference 类型数据，value 将根据（§2.8.3）中定义的转换规则转换为
     * value’，objectref 的指定字段的值将被设置为 value’。
     * @date: 10:54 2022/6/17
     **/
    @Override
    public void execute(StackFrame frame, ExecutionResult result) {
        //获取字段名
        ConstantFieldRefInfo constantFieldRefInfo = (ConstantFieldRefInfo) getConstantInfo(getIndex());
        String fieldName = constantFieldRefInfo.getFieldName();

        JavaObject fieldValue = frame.getOperandStack().pop();
        JavaObject objectRef = frame.getOperandStack().pop();
        //给对象设置属性
        objectRef.setFieldValue(fieldName, fieldValue);
    }

}
